package com.wytec.xywzxw.controller;

import cn.hutool.core.date.DateUtil;
import cn.xuyanwu.spring.file.storage.FileInfo;
import cn.xuyanwu.spring.file.storage.FileStorageService;
import com.wytec.xywzxw.utils.CommonUtils;
import com.wytec.xywzxw.utils.EmailUtils;
import com.wytec.xywzxw.bean.commonBean.CommonResult;
import com.wytec.xywzxw.bean.commonBean.FileRespBean;
import com.wytec.xywzxw.utils.QiNiuUtils;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.mail.BodyPart;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.text.SimpleDateFormat;
import java.util.*;

@RestController
@Api(tags = "上传服务模块")
public class UpFileController extends BaseApiController{
    /**
     * sqlite数据库路径
     */
    @Value("${custom.sqlite-db-path}")
    private String databasePath;
    /**
     * 是否存储到数据库
     */
    @Value("${custom.use-database}")
    private boolean useDB;

    /**
     * 发件人的邮箱
     */
    @Value("${email.user}")
    private String emailSendUser;

    /**
     * 收件人的邮箱
     */
    @Value("${email.receive}")
    private String receiveUser;

    /**
     * 是否发送邮件
     */
    @Value("${email.send}")
    private boolean send;

    /**
     * 缩略图图片宽
     */
    @Value("${custom.thumbnail-w}")
    private int thumbImageW;

    /**
     * 缩略图图片高
     */
    @Value("${custom.thumbnail-h}")
    private int thumbImageH;

    /**
     * 文件上传服务
     */
    @Resource
    private FileStorageService fileStorageService;

    @Resource
    private QiNiuUtils qiNiuUtils;


    @GetMapping(value = "/list")
    @ApiOperation(value = "获取七牛文件列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "type", value = "0所有文件都整合在object中，1分类返回上传的文件"),
            @ApiImplicitParam(name = "prefix", value = "前缀")
    })
    public CommonResult<Object> getFileList(@RequestParam(defaultValue = "0", value = "type") int type, @RequestParam(defaultValue = "", value = "prefix") String prefix) {
        Map<String, Object> map = qiNiuUtils.getQiNiuBucketList(type, prefix);
        return CommonResult.success(map);
    }

    @ApiOperation(value = "上传文件")
    @PostMapping(value = "/upload", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
    @ApiImplicitParams({
            @ApiImplicitParam(name = "file", value = "上传的文件"),
            @ApiImplicitParam(name = "type", value = "qiniu,local,ftp,sftp"),
            @ApiImplicitParam(name = "use", value = "1使用原文件名  2系统生成新文件名")
    })
    public CommonResult<Object> uploadImage(@RequestPart(value = "file") MultipartFile file,
                                    @RequestParam(name = "type", required = false, defaultValue = "qiniu") String type,
                                    @RequestParam(name = "use", required = false, defaultValue = "1") Integer use) {
        try {
            // use 1 使用原文件名   2 使用随机数命名文件名
            // 原文件名
            String fileName = file.getOriginalFilename();
            // 获取扩展名
            List<String> split = Arrays.asList(fileName.split("\\."));
            String extName = split.stream().reduce((a, b) -> b).orElse(null);
            assert extName != null;
            // 图片的扩展名
            List<String> imgExt = Arrays.asList("jpg", "jpeg", "png", "gif", "bmp");
            List<String> videoExt = Arrays.asList("mp4", "avi", "mov");
            // 按照年月生成的文件夹名
            Date currentDate = new Date();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM");
            String formattedDate = sdf.format(currentDate);

            if (use == 2) {
                fileName = null;
            }

            FileInfo fileInfo = null;
            if (imgExt.contains(extName.toLowerCase())) {
                // 图片
                fileInfo = fileStorageService
                        .of(file)
                        .setPlatform(type)    //使用指定的存储平台
                        .thumbnail(th -> th.size(thumbImageW, thumbImageH))  //再生成一张设定大小的缩略图
                        .setSaveFilename(fileName)
                        .setThumbnailSuffix(".min." + extName)
                        .setPath("images/" + formattedDate + "/")
                        .upload();

            } else if (videoExt.contains(extName.toLowerCase())) {
                // 视频
                fileInfo = fileStorageService
                        .of(file)
                        .setPlatform(type)
                        .setSaveFilename(fileName)
                        .setPath("videos/" + formattedDate + "/")
                        .upload();
            } else {
                // 非图片视频
                fileInfo = fileStorageService
                        .of(file)
                        .setPlatform(type)
                        .setSaveFilename(fileName)
                        .setPath("files/" + formattedDate + "/")
                        .upload();
            }

            if (fileInfo == null) {
                return CommonResult.failed("上传失败");

            } else {
                // 处理数据返回
                FileRespBean fileRespBean = new FileRespBean();
                fileRespBean.setBasePath(fileInfo.getBasePath() + fileInfo.getPath());
                if (fileInfo.getUrl() != null) {
                    fileRespBean.setFileName(fileInfo.getFilename());
                    fileRespBean.setUrl(fileInfo.getUrl());
                    fileRespBean.setSize(fileInfo.getSize() == 0 ? null : fileInfo.getSize().toString());
                    // 插入数据库
                    insert2DB(fileInfo);
                    //发送email
                    sendEmail(fileInfo);

                }
                if (fileInfo.getThUrl() != null) {
                    fileRespBean.setThFileName(fileInfo.getThFilename());
                    fileRespBean.setThUrl(fileInfo.getThUrl());
                    fileRespBean.setThSize(fileInfo.getThSize() == 0 ? null : fileInfo.getThSize().toString());
                }
                return CommonResult.success(fileRespBean);
            }
        } catch (Exception e) {
            return CommonResult.failed(e.getMessage());
        }
    }

    private void insert2DB(FileInfo fileInfo) {
        if (!useDB) return;
        try {
            Class.forName("org.sqlite.JDBC");
            //SQLite 数据库文件
            String url = "jdbc:sqlite:" + databasePath;
            Connection conn = DriverManager.getConnection(url);
            String sql = "insert into upload" +
                    "(`name`,`platform`,`path`,`type`,`size`,`url`,`create_time`,`th_size`,`th_url`) " +
                    "values (?,?,?,?,?,?,?,?,?)";
            PreparedStatement ps = conn.prepareStatement(sql);
            ps.setObject(1, fileInfo.getFilename());
            ps.setObject(2, fileInfo.getPlatform());
            ps.setObject(3, fileInfo.getBasePath() + fileInfo.getPath());
            ps.setObject(4, fileInfo.getContentType());
            ps.setObject(5, fileInfo.getSize());
            ps.setObject(6, fileInfo.getUrl());
            ps.setObject(7, System.currentTimeMillis());
            ps.setObject(8, fileInfo.getThUrl() != null ? fileInfo.getThSize() : 0);
            ps.setObject(9, fileInfo.getThUrl());

            ps.executeUpdate();
            ps.close();
            conn.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void sendEmail(FileInfo fileInfo) {
        if (!send) return;
        String content = "";
        try {
            InputStream in = new ClassPathResource("ftl/upfile_email_notify.ftl").getInputStream();
            byte[] data = new byte[1024];
            int len;
            while ((len = in.read(data)) != -1) {
                content += new String(data, 0, len);
            }
            in.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        Map<String, String> param = new HashMap<>();
        param.put("{{filename}}", fileInfo.getFilename());
        param.put("{{platform}}", fileInfo.getPlatform());
        param.put("{{path}}", fileInfo.getBasePath() + fileInfo.getPath());
        param.put("{{size}}", CommonUtils.getConversionFlows(fileInfo.getSize().toString()));
        param.put("{{url}}", fileInfo.getUrl());
        param.put("{{date}}", DateUtil.date().setTimeZone(TimeZone.getTimeZone("Asia/Shanghai")).toString("yyyy-MM-dd HH:mm:ss"));
        param.put("{{send_user}}", "邮件管理员");
        for (String key : param.keySet()) {
            content = content.replace(key, param.get(key));
        }

        //	创建Session会话
        Session session = EmailUtils.createSession();
        //	创建邮件对象
        MimeMessage message = new MimeMessage(session);
        try {
            message.setSubject("收到文件上传");
            message.setFrom(new InternetAddress(emailSendUser));
            message.setRecipient(MimeMessage.RecipientType.TO, new InternetAddress(receiveUser));

            //	邮件主体
            BodyPart textPart = new MimeBodyPart();
            textPart.setContent(content, "text/html;charset=utf-8");
            Multipart multipart = new MimeMultipart();
            multipart.addBodyPart(textPart);

            //	将邮件装入信封
            message.setContent(multipart);

            //	发送
            Transport.send(message);
        } catch (Exception e) {
            e.printStackTrace();

        }
    }
}
